package com.abc.fast.server.user.aspect;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.abc.fast.common.domain.entity.Log;
import com.abc.fast.common.domain.enums.LogStatusEnum;
import com.abc.fast.common.domain.model.LoginUser;
import com.abc.fast.common.manager.AsyncManager;
import com.abc.fast.common.utils.SecurityUtil;
import com.abc.fast.common.utils.ip.IpUtil;
import com.abc.fast.common.utils.ServletUtil;
import com.abc.fast.server.user.service.handler.UserAsyncHandler;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * AOP日志
 * @Author LiJunXi
 * @Date 2024-03-03 21:11
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    // 计算操作消耗时间
    private static final ThreadLocal<Long> TIME_THREAD_LOCAL = new NamedThreadLocal<Long>("Cost Time");


    /**
     * 定义一个切点
     */
    @Pointcut("execution(* com..controller..*.*(..))")
    public void controllerPointcut() {
    }

    /**
     * 处理请求前执行
     * @param joinPoint 切点
     */
    @Before("controllerPointcut()")
    public void boBefore(JoinPoint joinPoint) {
        TIME_THREAD_LOCAL.set(System.currentTimeMillis());
    }

    /**
     * 处理完请求后执行
     * @param joinPoint 切点
     */
    @AfterReturning(value = "controllerPointcut()", returning = "jsonResult")
    public void doAfterThrowing(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    private void handleLog(JoinPoint joinPoint, Exception e, Object jsonResult) {
        try {
            Log logRecord = new Log();
            // IP地址
            logRecord.setRequestIp(IpUtil.getIpAddr());
            // 请求URL
            logRecord.setRequestUrl(ServletUtil.getRequest().getRequestURI());
            // 请求方式
            logRecord.setRequestType(ServletUtil.getRequest().getMethod());
            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            logRecord.setMethodName(className + "." + methodName + "()");
            // 请求状态
            if (Objects.nonNull(e)){
                logRecord.setStatus(LogStatusEnum.ERROR.getStatus());
                logRecord.setErrorMsg(StrUtil.sub(e.getMessage(), 0, 255));
            } else {
                logRecord.setStatus(LogStatusEnum.NORMAL.getStatus());
            }
            // 用户信息
            LoginUser loginUser = SecurityUtil.getLoginUser();
            if (Objects.nonNull(loginUser)){
                logRecord.setUserId(loginUser.getUserId());
            }
            // 请求参数
            List<Object> paramList = Stream.of(joinPoint.getArgs())
                .filter(args -> !(args instanceof ServletRequest))
                .filter(args -> !(args instanceof ServletResponse))
                .collect(Collectors.toList());
            String printParamStr = paramList.size() == 1 ? JSONUtil.toJsonStr(paramList.get(0)) : JSONUtil.toJsonStr(paramList);
            logRecord.setRequestParam(printParamStr);
            // 返回结果
            logRecord.setRespResult(JSONUtil.toJsonStr(jsonResult));
            // 消耗时间
            logRecord.setCostTime(System.currentTimeMillis() - TIME_THREAD_LOCAL.get());
            // 保存数据库
            AsyncManager.me().execute(UserAsyncHandler.saveLog(logRecord));

        } catch (Exception exp){
            log.error("异常信息:{}", exp.getMessage());
            e.printStackTrace();
        }
    }


}
